import 'dart:core';

main(List<String> args) {
  // nullTest();
  // dynamicTest();
  numTest();
}

void dynamicTest() {
  dynamic b;
  print(b.runtimeType); // Null
  dynamic c = "123";
  print(c.indexOf("3")); // 输出2
  print(c.abs()); // 编译不报错，运行时错误
}

/// 说明，未初始化的变量都是Null 类型，调用未初始化的对象的方法会报 NoSuchMethodError 错误
void nullTest() {
  int a;
  print(a.runtimeType); // Null
  a.abs(); // 运行时错误
  // 报错，Unhandled exception:
  // NoSuchMethodError: The method 'abs' was called on null.
  // Receiver: null
  // Tried calling: abs()
}

/// num 有两个子类： int 和 double ，int 和double 之间不能相互转换
void numTest() {
  // 第一种情况:
  // int a = 0;
  // double b = a; // 编译错误，因为int 和 double 不能强转

  // 第二种情况:
  // var a = 1;
  // double b = a; // 编译错误，因为,a被推断成为int。

  // 第三种情况：
  // num a = 1;
  // double b = a; // 运行时错误， 1 是 int 实例。（这个要特别小心，将父类的值赋值给子类很危险）

  // double a = 1; // 这个是正确的，dart 2.1 可以将整形字面量赋值给double.

  // 如何做到int和double通用：
  var a = 1;
  var b = 1.1;
  b = a.toDouble();
}

/// bool  类型只有两个编译时常量 true 和 false，条件语句必须是bool类型
void boolTest() {
  bool a;
  print(a.runtimeType); // Null， bool类型不初始化，也是null

  // int b = 0;
  // if (b) {
  //   // 编译错误,因为b不是bool类型
  //   print(b);
  // }
}

/// 字符串默认编码是utf-16
/// 使用单引号或者双引号
/// 字符串字面量是编译常量
/// == 号判断是如果字符串内容相等，就相等。不需要两个对象是同一个对象.
/// + 连接两个字符串
/// ${} 字符串差值
/// ''' 创建多行字符串
/// 实现[]下标，可以通过索引得到字符
void stringTest() {}

/// as 类型转换 （当你确定了是指定类型后，才能使用as，否则会有运行时错误）
/// is 类型判断。（obj 实现了T接口， obj is T 才是true）(obj is Object 总是true)
/// is!
///
void typeTransform() {
  var a;
  (a as int).abs(); // 运行时错误，因为a是Null类型

  // 先加判断，条件语句里可以直接使用a.abs()，不会包编译错误
  if (a is int) {
    a.abs();
  }
}
